#include "util/common.hxx"
#include <time.h>
#include <iostream>

namespace utility {

std::string itoa(uint32_t n) {

    std::ostringstream oss;
    oss<<n;

    return oss.str();
}

uint32_t atoi(const std::string& str) {

    std::istringstream iss(str);
    int n;
    iss>>n;

    return n;
}


typedef void*(THREADFUNC) (void *arg);

int64_t startThread(THREADFUNC* func, void* arg) {
    
    pthread_t thread_id = -1;
    pthread_create(&thread_id, NULL, func, arg);

    return thread_id;
}

int waitThread(pthread_t thread_id) {
    
    int ret = pthread_join(thread_id, NULL);
    return ret;
}


int thread_cond_timewait(pthread_cond_t* cond, pthread_mutex_t* mutex, uint64_t sec) {

    struct timespec to;

    clock_gettime(CLOCK_REALTIME, &to);

    to.tv_sec += sec;
    to.tv_nsec = 0;

    return pthread_cond_timedwait(cond, mutex, &to);
}

void sleepnano(uint64_t time) {
    
    struct timespec ts;
    ts.tv_sec = time/1000000000;
    ts.tv_nsec = (time%1000000000);

    nanosleep(&ts, NULL);
}

uint64_t nowMicros() {
    
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
}


timespec getnow()
{
    timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);

    return now;
}

//milliseconds bw two timespec
int64_t gapBetween(const timespec& t1, const timespec& t2)
{
    int64_t ms1 = t1.tv_sec * 1000 + t1.tv_nsec/1000000;
    int64_t ms2 = t2.tv_sec * 1000 + t2.tv_nsec/1000000;

    return (ms2 - ms1);
}


PerformanceMeasure::PerformanceMeasure(const std::string& name) {
    
    m_num = 0;
    m_sum = 0;
    m_name = name;
}

PerformanceMeasure::~PerformanceMeasure() {

    std::cout<<m_name<<": "<<avg()<<" "<<m_num<<" "<<m_sum<<std::endl;
}

void PerformanceMeasure::start() {
    
    m_start = nowMicros();
}

void PerformanceMeasure::end() {
    
    m_end = nowMicros();
    m_num++;
    m_sum += m_end - m_start;
}


double PerformanceMeasure::avg() {
    
    if(m_num == 0) return -1;

    return m_sum/m_num;
}


uint64_t PerformanceMeasure::getNum() {

    return m_num;
}

uint64_t PerformanceMeasure::getCur() {

    return m_end - m_start;
}

}

